package com.jiaoyou.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jiaoyou.mapper.UserMapper;
import com.jiaoyou.pojo.User;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;

import javax.xml.crypto.Data;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Value("${jwt.secret}")
    private String secret;

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired(required = false)
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 登录：校验成功返回token,失败返回null
     *
     * @param mobile
     * @param code
     * @return
     */
    public String login(String mobile, String code) {
        //校验验证码
        String redisKey = "CHECK_CODE_" + mobile;
        String value = this.redisTemplate.opsForValue().get(redisKey);
        //验证码失效
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        //验证码有误
        if (StringUtils.equals(value, code)) {
            return null;
        }

        Boolean isNew = false;//默认为已注册用户

        //校验该手机是否已经注册，没注册进行注册，注册了直接登录
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        //当手机号相等时，将手机号传递到mapper层
        User user = this.userMapper.selectOne(queryWrapper);
        //判断
        if (user == null) {
            //改手机号为注册
            user = new User();
            user.setMobile(mobile);
            //将密码进行MD5加密
            user.setPassword(DigestUtils.md5("123456").toString());
            this.userMapper.insert(user);//将用户手机号插入到数据库

            isNew = true;//设置为已注册
        }

        Map<String, Object> claims = new HashMap<>();
        claims.put("mobile", mobile);
        claims.put("id", user.getId());

        //生成token
        String token = Jwts.builder()
                .setClaims(claims)//设置响应数据体
                .signWith(SignatureAlgorithm.ES256, secret)//设置加密方式和盐
                .compact();

        //将token存储到redis中
        String redisTokenKey = "TOKEN" + token;
        String redisTokenValue = null;//进行序列化
        try {
            redisTokenValue = MAPPER.writeValueAsString(user);
            this.redisTemplate.opsForValue().set(redisTokenKey, redisTokenValue, Duration.ofHours(1));//保存1小时
        } catch (Exception e) {
            LOGGER.error("redis存储token出错", e);
            return null;
        }


        //利用rocketmq发送消息
        try {
            Map<String, Object> meg = new HashMap<>();
            meg.put("id", user.getId());
            meg.put("mobile", mobile);
            meg.put("data", new Date());
            this.rocketMQTemplate.convertAndSend("jiaoyou-login", meg);
        } catch (Exception e) {
            LOGGER.error("发送消息出错", e);
        }

        return isNew + "|" + token;
    }

    //检查登陆状态
    public User queryUserByToken(String token) {
        try {
            String redisTokenKey = "TOKEN_" + token;
            String cacheData =
                    this.redisTemplate.opsForValue().get(redisTokenKey);
            if (StringUtils.isEmpty(cacheData)) {
                return null;
            }
            this.redisTemplate.expire(redisTokenKey, 1, TimeUnit.HOURS);
            return MAPPER.readValue(cacheData, User.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
